C তে socket
প্রোগ্রামিং করার সময় Non-Blocking এবং Asynchronous সকেট ব্যবহার করে আপনি একাধিক ক্লায়েন্টের সাথে একযোগে যোগাযোগ করতে পারেন, তা সিস্টেমের কোনো থ্রেড বা প্রসেসকে ব্লক না করেই। এতে নেটওয়ার্ক অপারেশনগুলো ব্লক করবে না এবং প্রোগ্রামটি অন্যান্য কাজ করতে সক্ষম হবে।
এই দুটি কৌশল select()
, poll()
বা epoll()
মতো সিস্টেম কল ব্যবহার করে একাধিক সকেটকে পরিচালনা করা সম্ভব করে।
Non-Blocking সকেট সাধারণত সার্ভার প্রোগ্রামিংয়ে ব্যবহৃত হয়, যেখানে সার্ভার সকেট ক্লায়েন্টের সংযোগের জন্য অপেক্ষা না করে অন্যান্য কার্যক্রম সম্পাদন করতে পারে। যখন একটি সকেট নন-ব্লকিং মোডে থাকে, তখন read()
বা write()
ফাংশনগুলো যদি কোনো ডেটা না পায়, তবে তা অবিলম্বে একটি নির্দিষ্ট ত্রুটি প্রদান করে এবং প্রোগ্রামটি ব্লক হওয়ার পরিবর্তে অন্যান্য কাজ করতে থাকে।
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/select.h>
#define PORT 65432
int main() {
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[1024];
// সার্ভার সকেট তৈরি
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// সার্ভারের IP এবং পোর্ট সেট করা
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// সার্ভার সকেটে বাইন্ড করা
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// লিসেনিং শুরু করা
if (listen(server_socket, 5) == -1) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
// নন-ব্লকিং সকেট তৈরি
int flags = fcntl(server_socket, F_GETFL, 0);
fcntl(server_socket, F_SETFL, flags | O_NONBLOCK);
printf("Server is listening on port %d...\n", PORT);
// ক্লায়েন্টের সংযোগের জন্য অপেক্ষা
while (1) {
client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
if (client_socket == -1) {
// নন-ব্লকিং মোডে কোনো ক্লায়েন্ট না আসলে, সার্ভার অন্য কাজ করতে পারে
printf("No client connection, doing other work...\n");
sleep(1); // কিছু সময়ের জন্য বিরতি, অন্য কাজ করার জন্য
} else {
// ক্লায়েন্টের সাথে সংযোগ স্থাপন হলে
printf("Client connected\n");
read(client_socket, buffer, sizeof(buffer));
printf("Received: %s\n", buffer);
close(client_socket);
}
}
close(server_socket);
return 0;
}
fcntl()
ব্যবহার করে সার্ভার সকেটের ফ্ল্যাগ পরিবর্তন করা হয়েছে, যাতে এটি নন-ব্লকিং মোডে চলে।accept()
কলের মধ্যে কোনো ক্লায়েন্ট না আসলে, এটি অবিলম্বে একটি ত্রুটি দেবে এবং সার্ভার অন্য কাজ করতে থাকবে।Asynchronous সকেটের মাধ্যমে প্রোগ্রামটি কোনো একক থ্রেড বা প্রসেস ব্যবহার না করে, একাধিক সকেটের সাথে যোগাযোগ স্থাপন করতে পারে। এটি সাধারণত select()
বা epoll()
ব্যবহার করে একযোগভাবে একাধিক সকেট থেকে ডেটা গ্রহণ এবং পাঠানোর জন্য ব্যবহৃত হয়। এই পদ্ধতিতে, সকেটগুলোর মাধ্যমে যোগাযোগকে একযোগভাবে পরিচালনা করা যায়।
select()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <arpa/inet.h>
#define PORT 65432
#define MAX_CLIENTS 10
int main() {
int server_socket, client_socket, max_sd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[1024];
fd_set readfds;
// সার্ভার সকেট তৈরি
server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// সার্ভারের IP এবং পোর্ট সেট করা
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
// সার্ভার সকেটে বাইন্ড করা
if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// লিসেনিং শুরু করা
if (listen(server_socket, 5) == -1) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
printf("Server is listening on port %d...\n", PORT);
// `select()` ব্যবহারের জন্য সকেট সেটআপ
FD_ZERO(&readfds);
FD_SET(server_socket, &readfds);
max_sd = server_socket;
// ক্লায়েন্টের সংযোগের জন্য অপেক্ষা
while (1) {
fd_set tempfds = readfds;
int activity = select(max_sd + 1, &tempfds, NULL, NULL, NULL);
if (activity == -1) {
perror("select error");
exit(EXIT_FAILURE);
}
// নতুন সংযোগ পাওয়া গেলে
if (FD_ISSET(server_socket, &tempfds)) {
client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_len);
if (client_socket == -1) {
perror("Accept failed");
continue;
}
printf("New client connected\n");
FD_SET(client_socket, &readfds);
if (client_socket > max_sd) max_sd = client_socket;
}
// সকেট থেকে ডেটা পড়া
for (int i = 0; i <= max_sd; i++) {
if (FD_ISSET(i, &tempfds)) {
int valread = read(i, buffer, sizeof(buffer));
if (valread == 0) {
printf("Client disconnected\n");
close(i);
FD_CLR(i, &readfds);
} else {
printf("Received from client: %s\n", buffer);
send(i, "Message received", 16, 0);
}
}
}
}
close(server_socket);
return 0;
}
select()
ব্যবহার: select()
ফাংশন একাধিক সকেটের জন্য অপেক্ষা করে এবং যখন কোনো সকেট প্রস্তুত থাকে (যেমন ক্লায়েন্ট থেকে ডেটা আসে), তখন তা যথাযথভাবে পড়া হয়।select()
, poll()
, বা epoll()
ব্যবহারের মাধ্যমে আপনি একাধিক সকেটকে একযোগভাবে পরিচালনা করতে পারবেন, যা মাল্টি-ক্লায়েন্ট সার্ভারের জন্য অত্যন্ত উপকারী।এই দুটি কৌশলই উচ্চ পারফরম্যান্স এবং স্কেলেবল নেটওয়ার্ক অ্যাপ্লিকেশন তৈরি করতে সাহায্য করে, যেখানে একাধিক ক্লায়েন্টের সাথে একযোগে কাজ করা সম্ভব।
common.read_more